﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Data;

namespace DymaticMethod
{
    class MyLCG
    {
        delegate void CopyPublicPropertiesDelegate<T, TU>(T source, TU target);
        static Dictionary<string, object> _del = new Dictionary<string, object>();

        public class PropertyMap
        {
            public PropertyInfo SourceProperty { get; set; }
            public PropertyInfo TargetProperty { get; set; }
        }

        private static Dictionary<string, PropertyMap[]> _maps = new Dictionary<string, PropertyMap[]>();

        public static void GenerateCopyDelegate<T, TU>()
        {
            var className = GetClassName(typeof(T), typeof(TU));
            var args = new[] { typeof(T), typeof(TU) };
            var mod = typeof(Program).Module;

            var dm = new DynamicMethod(className, null, args, mod);
            var il = dm.GetILGenerator();
            var maps = _maps[className];

            foreach (var map in maps)
            {
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Ldarg_0);
                il.EmitCall(OpCodes.Callvirt,
                            map.SourceProperty.GetGetMethod(), null);
                il.EmitCall(OpCodes.Callvirt,
                            map.TargetProperty.GetSetMethod(), null);
            }
            il.Emit(OpCodes.Ret);
            var del = (CopyPublicPropertiesDelegate<T, TU>)dm.CreateDelegate(typeof(CopyPublicPropertiesDelegate<T, TU>));
            _del.Add(className, del);
        }

        private static string GetClassName(Type sourceType, Type targetType)
        {
            var keyName = "Copy_";
            keyName += sourceType.FullName.Replace(".", "_");
            keyName += "_";
            keyName += targetType.FullName.Replace(".", "_");
            return keyName;
        }

    }
}
